CLI开发:递归处理json文件及路径
概述
本节实现 CLI 工具中模板文件处理的核心逻辑,重点处理 JSON 配置对象的递归遍历和文件路径拼接。根据用户交互结果(单选字符串 / 布尔值 / 嵌套对象)生成不同的模板路径。
模板配置对象结构
用户交互结果示例
{
"css": "tailwind",
"cdn": true,
"pwa": false,
"electrons": true,
"router": {
"mode": "history",
"guard": true
}
}
json
三种响应类型处理
| 响应类型 | 示例字段 | 处理方式 |
|---|---|---|
| 字符串(单选) | css: "tailwind" | 拼接为 templates/css/tailwind/ |
| 布尔值 | cdn: true | 布尔为 true 时拼接对应目录 |
| 对象(嵌套) | router: { ... } | 递归遍历子属性 |
路径拼接逻辑
字符串类型处理
// 当 restFileName 是 string 类型时,拼接嵌套路径
if (typeof restFileName === 'string') {
const templatePath = `templates/${fileName}/${restFileName}`
// 继续处理该目录下的文件
}
typescript
递归遍历实现
import fs from 'fs-extra'
import path from 'path'
interface ProcessOptions {
src: string
dest: string
config: Record<string, any>
}
async function workFiles(src: string, options: ProcessOptions): Promise<void> {
const entries = await fs.readdir(src, { withFileTypes: true })
for (const entry of entries) {
const currentPath = path.join(src, entry.name)
if (entry.isDirectory()) {
// 递归处理子目录
await workFiles(currentPath, options)
} else {
// 处理文件:复制到目标路径
const destPath = path.join(options.dest, path.relative(options.src, currentPath))
await fs.copy(currentPath, destPath)
}
}
}
typescript
文件处理流程
用户交互结果 (config 对象)
│
▼
遍历 config 的每个 key-value
│
├── value 是 string → templates/{key}/{value}/ → 复制文件
│
├── value 是 boolean → true 时 templates/{key}/ → 复制文件
│
└── value 是 object → 递归处理嵌套结构
│
▼
workFiles(src, options)
│
├── 目录 → 递归
└── 文件 → 复制
text
常见问题与修复
Bug: 扩展名文件被错误拷贝
test 目录中 .ejs 模板文件被原样拷贝到输出目录,需要在文件过滤逻辑中排除模板文件:
// 过滤非模板文件
if (!entry.name.endsWith('.ejs')) {
await fs.copy(currentPath, destPath)
}
typescript
修正 base 目录遍历
用户传递的 options 中基础目录(base)需要默认读取:
// 处理 base 目录(始终需要读取)
const basePath = path.join(templatesDir, 'base')
await workFiles(basePath, options)
typescript
关键要点
- CLI 模板处理涉及三种数据类型:字符串、布尔值、嵌套对象
workFiles函数定义为异步方法,放在process-templates模块中以便访问options- 文件路径拼接使用模板字符串:
templates/${fileName}/${restFileName} - 需过滤
.ejs模板文件,避免原样拷贝到输出目录 configPage参数需使用instanceof Array精确判断数组类型
↑